Welcome back. The scope of a variable is
the set of statements where a variable name can be accessed.
In the function square,
on line two, we assign y to have a value.
Since that assignment is inside the function definition,
the scope is only the rest of that function definition.
On line six, we really can't refer to y.
In fact, we really can't refer to y.
We get an error. On line six,
the error message is telling us the name y is not defined,
and that's true even though line two will already have executed,
line five causes the square function to run.
So, line two will have executed, but even so,
we say that that variable y was local to the function square,
and its scope is local,
we can't access it out here on line six.
Now, suppose we had a variable y at the top level outside of any function definition.
Say, we did y equals five.
Now, when we get to line six,
y will be defined,
but the value will be five and not 100.
What we get is the value five that we signed on line
four and not the value 100 that we would have assigned on line two.
It's going to help to introduce a little vocabulary here,
the idea of a namespace.
A namespace is an environment where all names are unique.
The city of Ann Arbor, Michigan,
we can only have one Main Street and a single stadium, boulevard.
That names can be reuse in other namespaces.
Other cities have a street named Main Street,
but it doesn't refer to our street, it refers to theirs.
In Python, there was one global or top-level namespace.
Then, each invocation of a function creates a new namespace.
In CodeLens, we show these namespaces as stack frames.
There's a global frame where we've defined square and we've defined y,
and then we invoke the square function that creates
a new stack frame and CodeLens is nice enough to label it for us.
It says, "This is the stack frame for the invocation of the square function."
The behind the scenes assignment where the formal parameter name
x got its value of 10 because we passed in the value 10 for it,
that goes into the local stack frame.
That's in the local namespace for the invocation of square.
Then, we set y to be 100.
That's also in the local stack frame.
So, it's really interesting to notice here,
we've got y is five,
we've got y is 100.
This works just fine because they're different namespaces.
Just like we have Main Street and Ann Arbor and Main Street in another city,
we can have Y in the global frame and y in the local frame.
So, here's the gory details of
how variable lookup and variable assignment work with namespaces.
I'm just going to adjust this example slightly.
The first rule is if you refer to a variable in the code inside a function,
if that variable name is ever assigned a value inside the function definition,
even further on in that function definition,
then it treats the reference as local.
If it finds the value on the local stack frame,
it uses that value and otherwise, it's an error.
So, here, it's going to be an error on line two.
We are referring to the variable y,
y is assigned a value somewhere in
the square function which means that y should be a local variable throughout,
but when we are on line two,
y doesn't have a value.
It does not go and get the y equals five from the global stack frame.
It just says, "Y is referenced before assignment on line two."
So, that's an error.
If, however, the variable name is never assigned a value inside the function definition,
then it will look in the global stack frame.
Suppose I do, w equals q plus one,
well, let's show it in CodeLens so we can really see what's happening.
Define all these variables in the global frame,
and now, we start running square.
So, we get to line two,
it tries to look up q. Q is never going to be a local variable in the square function,
so therefore, when we look up q,
it'll go look it up in the global frame.
We get seven, add one to it,
and w gets the value eight.
So, if we look up a reference to
a variable and that variable is ever local inside the function,
it's got to look it up only in the local frame.
It's never going to be a local variable in
that function than it looks it up in the global frame.
This can be pretty confusing and your programs will be a lot easier to understand
if all of your variable references are just references in the local frame.
So, my recommendation is avoid referring to global variables
inside a function definition. Don't do this.
It's legal Python, but it's not a good idea.
Make another formal parameter for the function and have
whatever value you need to get passed in as a parameter to the function.
So, that's how variable lookups references happen inside of functions.
What about assignment inside a function?
Assignment is always done in the local namespace,
the stack frame for that function call.
So, if we go back to our original code,
notice that line two creates a variable y on the local stack frame.
So, there's already a y in the global frame.
But when we get to line two,
we create one in the local stack frame.
So, the rule for assignments is that we're always assigning to a local variable.
There are actually easy way to force lookup an assignment
inside of a function to use the global stack frame.
I'm going to show you how to do this for your understanding,
but don't do it in your programs.
It'll lead to confusing programs that are hard to debug.
Other programmers will shun you.
You'll have no friends and you'll live a miserable life,
okay, and it won't be that bad.
But just don't do this.
I'm going to show you for your understanding.
I can declare y to be global.
If I now say w equals y plus one,
again, don't do this just so you can understand it.
Y is five on the global frame.
We say please treat y as the global y.
Now, line three works because we can get to
the y equals five and w gets to be the value six.
Now, we're going to change y in the global frame,
and we're going to return our 100.
So, this is doable that it leads to very confusing code.
That's local and global variables for you.
Inside a function definition,
variable assignments create local variables.
They can't be referenced outside the code for
that function and that includes the formal parameters of the function.
Those will also be local variables.
Variable references use the local version of the variable.
You can reference a global variable inside a function either by explicitly declaring it
global or by referencing
a variable name that is never assigned a value inside the function.
But your life will be better if you never do that and make all of your references
to variables inside of functions, the local references.
I'll see you next time.